import * as dayjs from 'dayjs';
import { Inject, Injectable } from '@nestjs/common';
import { DataService } from '../data/data.service';
import { OpenaiService } from 'src/libs/openai/openai.service';
import { RedisService } from 'src/libs/redis/redis.service';
import { ConfigService } from '../config/config.service';
import { PrismaService } from 'src/libs/prisma/prisma.service';
import { CombinationStatus, CombinationType, MatchStatus, UserRoleType } from '@prisma/client';
import { MatchData } from 'src/utils/init-data';
import { getDayOfWeekChinese } from 'src/utils';
import { getFreeBaseCountArray } from 'src/utils/contains';

export type RecommendItem = {
  id: string;
  type: CombinationType;
  combinationData: { matchId: string; prediction: string; matchData?: MatchData }[];
  advice: string;
  score: number;
  createTime: Date;
  updateTime: Date;
  status: CombinationStatus;
};

@Injectable()
export class FootballService {
  @Inject(DataService)
  private readonly dataService: DataService;
  @Inject(OpenaiService)
  private readonly openaiService: OpenaiService;
  @Inject(RedisService)
  private readonly redisService: RedisService;
  @Inject(ConfigService)
  private readonly configService: ConfigService;
  @Inject(PrismaService)
  private readonly prismaService: PrismaService;

  /** 获取每日比赛数据 */
  async getDailyMatches(date: string, onlyToday?: boolean, userId?: string) {
    let analysisMatches: any[] = [];
    let showAnalysis = false;

    // 1 如果用户存在，判断是否为 VIP
    if (userId) {
      const foundUser = await this.prismaService.user.findUnique({ where: { id: userId }, include: { userRole: true } });
      if (foundUser?.userRole?.role === UserRoleType.VIP) showAnalysis = true;
    }

    // 2.1 date 小于今日
    if (date && new Date(date) < new Date(dayjs(new Date()).format('YYYY-MM-DD'))) {
      showAnalysis = true;
      const startOfDay = new Date(new Date(date).getTime() - 24 * 60 * 60 * 1000);
      const endOfDay = new Date(new Date(date).getTime() + 2 * 24 * 60 * 60 * 1000);
      analysisMatches = await this.prismaService.match.findMany({
        where: { matchTime: { lte: endOfDay, gte: startOfDay } },
        include: { MatchAnalysis: true },
      });
    }
    // 2.2 date 大于等于今日
    else {
      // 只获取当日比赛数据
      if (onlyToday) {
        const today = dayjs(new Date()).format('YYYY-MM-DD');
        const startOfDay = new Date(new Date(today).getTime() - 24 * 60 * 60 * 1000);
        const endOfDay = new Date(new Date(today).getTime() + 2 * 24 * 60 * 60 * 1000);
        analysisMatches = await this.prismaService.match.findMany({
          where: { matchTime: { lte: endOfDay, gte: startOfDay } },
          include: { MatchAnalysis: true },
        });
      }
      // 获取剩余待开赛数据
      else {
        analysisMatches = await this.prismaService.match.findMany({
          where: { matchTime: { gte: new Date() } },
          include: { MatchAnalysis: true },
        });
      }
    }

    // 3 解析比赛数据
    const freeBaseCountArray = getFreeBaseCountArray();
    analysisMatches.forEach((item, itemIndex) => {
      item.matchData = JSON.parse(item.matchData as string);
      // 未登录 不允许查看比赛分析
      if (!userId || (!showAnalysis && !freeBaseCountArray.some((sortNum) => item?.matchData?.matchNum?.includes(sortNum)))) {
        item.MatchAnalysis = [];
        return;
      }
      item?.MatchAnalysis?.forEach((analysis) => {
        if (analysis.analysisData) analysis.analysisData = JSON.parse(analysis.analysisData);
      });
    });

    // 4 过滤非当天的比赛
    if (onlyToday || date !== dayjs(new Date()).format('YYYY-MM-DD')) {
      analysisMatches = analysisMatches.filter((item) => {
        return item.matchData?.matchNum?.includes(getDayOfWeekChinese(date));
      });
    }

    // 5 按照 matchTime 排序
    analysisMatches.sort((a, b) => {
      const timeA = a.matchTime ? new Date(a.matchTime).getTime() : 0;
      const timeB = b.matchTime ? new Date(b.matchTime).getTime() : 0;
      return timeA - timeB;
    });

    return analysisMatches;
  }

  /** 获取比赛分析数据 */
  async getMatchAnalysis(matchId?: number, userId?: string) {
    let showAnalysis = false;
    const freeBaseCountArray = getFreeBaseCountArray();

    // 1 如果用户存在，判断是否为 VIP
    if (userId) {
      const foundUser = await this.prismaService.user.findUnique({ where: { id: userId }, include: { userRole: true } });
      if (foundUser?.userRole?.role === UserRoleType.VIP) showAnalysis = true;
    }

    // 2 比赛结束，任何人都可以看
    const res = await this.prismaService.matchAnalysis.findUnique({ where: { matchId }, include: { Match: true } });
    if (res?.Match?.status !== MatchStatus.NOT_STARTED) showAnalysis = true;

    // 3 判断是否隐藏分析数据
    if (res) {
      res.analysisData = JSON.parse(res.analysisData as string);
      if (res.Match?.matchData) {
        res.Match.matchData = JSON.parse(res.Match.matchData as string);
      }
      const hasFreeBase = freeBaseCountArray.some((sortNum) => (res?.Match?.matchData as any as MatchData)?.matchNum?.includes(sortNum));
      if (!userId || (!showAnalysis && !hasFreeBase)) res.analysisData = null;
    }
    return res;
  }

  /** 获取推荐组合 */
  async getDailyRecommend() {
    const today = new Date();
    const startOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 1);
    const endOfDay = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 2);

    const recommendList = await this.prismaService.matchRecommendCombination.findMany({
      where: {
        createTime: { gte: startOfDay, lt: endOfDay },
      },
    });

    const returnList: RecommendItem[] = [];
    for (const item of recommendList) {
      const combinationData = (JSON.parse(item.combinationData as string) || []) as RecommendItem['combinationData'];
      for (const combination of combinationData) {
        const foundMatch = await this.prismaService.match.findUnique({
          where: { matchId: +combination.matchId },
        });
        const matchData = JSON.parse(foundMatch?.matchData as string) as MatchData;
        combination.matchData = matchData;
      }
      returnList.push({ ...item, combinationData });
    }

    return returnList.filter((item) => item.combinationData.length > 0 && item.combinationData.every((item) => item.matchData));
  }
}
